package com.wj.uninstall;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 应用程序卸载监控，入口调用方法：openUrlWhenUninstall(……)
 * Created by wenjin on 2017/3/29.
 */

public class UninstallUtils {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

// path：data/data/[packageNmae]/lib
    // url:跳转的页面，需要http://或https://开头
    /**
     * Native 方法
     *
     * @param dirStr    要监听的目录，传值：/data/data/{packageNmae}/lib
     * @param activity  Activity对象
     * @param action    android.intent.action.VIEW
     * @param actionData    要在浏览器中打开的URL
     * @param userSerial
     * @return
     * @author SHANHY
     * @date   2015年12月15日
     */
    public static native String startWork(String dirStr,String dataPackageDir, String activity, String action, String actionData, String userSerial);

    private static SharedPreferences sharedPreferences;
    private static SharedPreferences.Editor editor;

    /**
     * 在需要开启子进程监听的地方调用该方法
     *
     * @param context
     * @param openUrl
     * @author SHANHY
     * @date   2015年12月15日
     */
    public static String openUrlWhenUninstall(Context context, String openUrl) {
        sharedPreferences = context.getSharedPreferences("process", Context.MODE_PRIVATE);
        editor = sharedPreferences.edit();
        String pid = sharedPreferences.getString("pid", "0");
        if (checkChildProcess(context, pid)) {
            Log.i("OnAppUninstall", "已经开启过守护进程");
            return "已经开启过守护进程";
        }
        Log.i("OnAppUninstall", "执行开启过守护进程");
        String dataPackageDir = context.getApplicationInfo().dataDir;
        String dirStr = context.getApplicationInfo().dataDir + "/lib";// 监听lib目录是因为：lib目录在进行应用清理的时候不会被清理
        String activity = null;
        if (checkInstall(context, "com.android.browser")) {
            Log.i("OnAppUninstall","已安装browser");
            activity = "com.android.browser/com.android.browser.BrowserActivity";
        }else{
            Log.i("OnAppUninstall","没有安装browser");
        }
        String action = "android.intent.action.VIEW";
        String gpid;
        if (Build.VERSION.SDK_INT < 17) {
            gpid = startWork(dirStr, dataPackageDir, activity, action, openUrl, null);
        } else {//4.2以上的系统由于用户权限管理更严格，调用API有所区别
            gpid = startWork(dirStr, dataPackageDir, activity, action, openUrl, getUserSerial(context));
        }
        if (gpid != null && !gpid.equals("") && !gpid.equals("0")) {
            Log.i("OnAppUninstall", "获得守护进程pid-->" + gpid);
            editor.putString("pid", gpid);
            editor.commit();
        }
        return gpid;
    }

    /**
     * 检查安装
     *
     * @param context
     * @param packageName
     * @return
     */
    private static boolean checkInstall(Context context, String packageName) {
        try {
            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
            if (packageInfo == null) {
                return false;
            } else {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取 UserSerial
     *
     * @param ctx
     * @return
     */
    private static String getUserSerial(Context ctx) {
        Object userManager = ctx.getSystemService("user");
        if (userManager == null) {
            return null;
        }
        try {
            Method myUserHandleMethod = android.os.Process.class.getMethod("myUserHandle", (Class<?>[]) null);
            Object myUserHandle = myUserHandleMethod.invoke(android.os.Process.class, (Object[]) null);
            Method getSerialNumberForUser = userManager.getClass().getMethod("getSerialNumberForUser", myUserHandle.getClass());
            long userSerial = (Long) getSerialNumberForUser.invoke(userManager, myUserHandle);
            return String.valueOf(userSerial);
        } catch (NoSuchMethodException e) {
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        } catch (InvocationTargetException e) {
        }
        return null;
    }

    /**
     * 检查子进程
     *
     * @param context
     * @param mpid
     * @return
     * @author SHANHY
     * @date   2015年12月15日
     */
    private static boolean checkChildProcess(Context context, String mpid) {
        boolean resflag = false;
        int mypid = android.os.Process.myPid();
        Log.i("OnAppUninstall", "mypid-->" + mypid);
        BufferedReader in = null;
        long starttime = System.currentTimeMillis();
        List<Map<String, String>> listdata = new ArrayList<Map<String, String>>();
        try {
            Process p = Runtime.getRuntime().exec("ps");
            in = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line = null;
            String[] temp;
            boolean flag = false;
//          int length = 0;
            while ((line = in.readLine()) != null) {
                // Log.i("OnAppUninstall", "ps-->" + line);
                if (!flag) {
                    flag = true;
                    continue;
                }
                line = line.replaceAll(" +", " ");
                temp = line.split(" ");
//              System.out.println(context.getPackageName());
//              System.out.println(temp[8]);
                if (temp[8].trim().equals(context.getPackageName().trim()) && (temp[2].trim().equals(mypid + "") || temp[2].trim().equals("1"))) {
                    Log.i("OnAppUninstall", "get it");
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("pid", temp[1]);
                    map.put("pname", temp[8]);
                    listdata.add(map);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                in = null;
            }
        }
        long endtime = System.currentTimeMillis();
        long spendtime = endtime - starttime;
        for (int i = 0; i < listdata.size(); i++) {
            if (listdata.get(i).get("pid").equals(mpid)) {
                resflag = true;
            } else {
                Log.w("OnAppUninstall", "捕获到多余守护进程-->" + listdata.get(i).get("pid") + " " + listdata.get(i).get("pname"));
                try {
                    android.os.Process.killProcess(Integer.valueOf(listdata.get(i).get("pid").trim()));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
            }
            Log.i("OnAppUninstall", listdata.get(i).get("pid") + " " + listdata.get(i).get("pname"));
        }
        Log.i("OnAppUninstall", "spendtime-->" + spendtime);
        return resflag;
    }
}
